﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Text.RegularExpressions;
using com.tiyma.common;

namespace com.tiyma.components
{
    public class SocketCatchManager
    {
        /// <summary>
        /// 读取页面内容
        /// </summary>
        /// <param name="i_url"></param>
        /// <param name="i_enconding"></param>
        /// <returns></returns>
        public static string GetPageHTML(string i_url, string i_enconding)
        {
            string t_html = string.Empty;
            Encoding t_site_enconding = Encoding.GetEncoding(i_enconding);
            try
            {
                MyWebRequest t_request = null;
                t_request = MyWebRequest.Create(new Uri(i_url), t_request, false);
                t_request.m_timeout = 20 * 1000;
                MyWebResponse t_response = t_request.GetResponse();
                byte[] t_page_bytes = new byte[10240];
                int t_bytes = 0;
               
                StringBuilder t_sb_page_content = new StringBuilder();
                while ((t_bytes = t_response.m_socket.Receive(t_page_bytes, 0, 10240, SocketFlags.None)) > 0)
                {

                    t_sb_page_content.Append(t_site_enconding.GetString(t_page_bytes, 0, t_bytes));

                }
                t_html = t_sb_page_content.ToString();
                t_html = t_html.Replace("\r", "").Replace("\n", "").Replace("\r\n", "");
                if (t_html.IndexOf("HTTP 错误 404 - 文件或目录未找到") > -1)
                {
                    t_html = NetSiteCatchManager.ReadUrl(i_url, t_site_enconding);
                }
                return t_html;
            }
            catch (Exception ex)
            {
                LogHelper.Error(string.Format("读取小说章节{0}内容失败", i_url) + ex.ToString());
                t_html = NetSiteCatchManager.ReadUrl(i_url, t_site_enconding);
                return t_html;
            }
        }
    }

    public class MyWebResponse
    {
        public Uri m_response_uri;
        public string m_content_type;
        public int m_content_length;
        public WebHeaderCollection m_headers;
        public string m_header;
        public Socket m_socket;
        public bool m_keep_alive;



        public void Connect(MyWebRequest i_request)
        {
            m_response_uri = i_request.m_request_uri;

            m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint remoteEP = new IPEndPoint(Dns.Resolve(m_response_uri.Host).AddressList[0], m_response_uri.Port);
            m_socket.Connect(remoteEP);
        }
        public void SendRequest(MyWebRequest i_request)
        {
            m_response_uri = i_request.m_request_uri;

            i_request.m_header = i_request.m_method + " " + m_response_uri.PathAndQuery + " HTTP/1.0\r\n" + i_request.m_headers;
            m_socket.Send(Encoding.ASCII.GetBytes(i_request.m_header));
        }
        public void SetTimeout(int i_timeout)
        {
            m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, i_timeout * 1000);
            m_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, i_timeout * 1000);
        }
        public void ReceiveHeader()
        {
            m_header = "";
            m_headers = new WebHeaderCollection();

            byte[] bytes = new byte[10];
            while (m_socket.Receive(bytes, 0, 1, SocketFlags.None) > 0)
            {
                m_header += Encoding.ASCII.GetString(bytes, 0, 1);
                if (bytes[0] == '\n' && m_header.EndsWith("\r\n\r\n"))
                    break;
            }
            MatchCollection matches = new Regex("[^\r\n]+").Matches(m_header.TrimEnd('\r', '\n'));
            for (int n = 1; n < matches.Count; n++)
            {
                string[] strItem = matches[n].Value.Split(new char[] { ':' }, 2);
                if (strItem.Length > 0)
                    m_headers[strItem[0].Trim()] = strItem[1].Trim();
            }
            // check if the page should be transfered to another location
            if (matches.Count > 0 && (
                matches[0].Value.IndexOf(" 302 ") != -1 ||
                matches[0].Value.IndexOf(" 301 ") != -1))
                // check if the new location is sent in the "location" header
                if (m_headers["Location"] != null)
                {
                    try { m_response_uri = new Uri(m_headers["Location"]); }
                    catch { m_response_uri = new Uri(m_response_uri, m_headers["Location"]); }
                }
            m_content_type = m_headers["Content-Type"];
            if (m_headers["Content-Length"] != null)
                m_content_length = int.Parse(m_headers["Content-Length"]);
            m_keep_alive = (m_headers["Connection"] != null && m_headers["Connection"].ToLower() == "keep-alive") ||
                        (m_headers["Proxy-Connection"] != null && m_headers["Proxy-Connection"].ToLower() == "keep-alive");
        }
        public void Close()
        {
            m_socket.Close();
        }

    }

    public class MyWebRequest
    {
        public int m_timeout;
        public WebHeaderCollection m_headers;
        public string m_header;
        public Uri m_request_uri;
        public string m_method;
        public MyWebResponse m_response;
        public bool m_keep_alive;

        public MyWebRequest(Uri i_uri, bool i_keep_alive)
        {
            m_headers = new WebHeaderCollection();
            m_request_uri = i_uri;
            m_headers["Host"] = i_uri.Host;
            m_keep_alive = i_keep_alive;
            if (m_keep_alive)
                m_headers["Connection"] = "Keep-Alive";
            m_method = "GET";
        }
        public static MyWebRequest Create(Uri i_uri, MyWebRequest i_alive_request, bool i_keep_alive)
        {
            if (i_keep_alive &&
                i_alive_request != null &&
                i_alive_request.m_response != null &&
                i_alive_request.m_response.m_keep_alive &&
                i_alive_request.m_response.m_socket.Connected &&
                i_alive_request.m_request_uri.Host == i_uri.Host)
            {
                i_alive_request.m_request_uri = i_uri;
                return i_alive_request;
            }
            return new MyWebRequest(i_uri, i_keep_alive);
        }
        public MyWebResponse GetResponse()
        {
            if (m_response == null || m_response.m_socket == null || m_response.m_socket.Connected == false)
            {
                m_response = new MyWebResponse();
                m_response.Connect(this);
                m_response.SetTimeout(m_timeout);
            }
            m_response.SendRequest(this);
            m_response.ReceiveHeader();
            return m_response;
        }


    }
}
